require "json"
require "config/country_number.rb"
require "config/areacode.rb"


module CallcacheParserHelper
  
end

def test()
  @ccode_src.nil?
end

############################################################################################################
##
## Function: rollbackFileName
## This function takes out the marker, NEWEXT(supposedly .imported). This function is for debugging purpose.
## Once a file is imported .imported is attached to the file name.
##
#############################################################################################################

def rollback_file_names(fileroot)

  allfiles = Dir[File.join(fileroot, "*")]

  allfiles.each { |i|
    if File.ftype(i) == "directory"
      rollback_file_names(i)
    elsif File.ftype(i) == "file" and File.extname(i) == NEWEXT
      #print i
      newFileName = File.rename(i, i.gsub(NEWEXT, ""))
    end
  }
end

###############################################################################################
##
## =>           Supporting Functions
##
###############################################################################################

def find_trunk_group_carrier(
  src_carrier \
  , src_ip \
  , dest_vcb \
  , trunk_group_col_name \
  , trunk_group_provider_name \
  , identifying_phone_number \
  , mask \
  , iso_country_code)

####
####
#### TODO: dest_vcb is not considered to distinguish trunk group it is used to get datacenter infor
  trunk_group_carrier = DimenTrunkGroupCarrier.find( \
  :first, \
  :conditions => \
  ["src_carrier=? \
      and src_ip=? \
      and trunk_group_col_name=? \
      and trunk_group_provider_name=? \
      and identifying_phone_number=?" \
    , src_carrier.to_s \
    , src_ip.to_s \
    , trunk_group_col_name.to_s \
    , trunk_group_provider_name.to_s \
    , identifying_phone_number.to_s])

  if trunk_group_carrier == nil
  trunk_group_carrier                           = DimenTrunkGroupCarrier.new
  trunk_group_carrier.src_carrier               = src_carrier.to_s
  trunk_group_carrier.src_ip                    = src_ip.to_s
  trunk_group_carrier.dimen_dest_vcb            = dest_vcb
  trunk_group_carrier.trunk_group_col_name      = trunk_group_col_name.to_s
  trunk_group_carrier.trunk_group_provider_name = trunk_group_provider_name.to_s
  trunk_group_carrier.identifying_phone_number  = identifying_phone_number.to_s
  trunk_group_carrier.mask                      = mask.to_s
  trunk_group_carrier.iso_country_code          = iso_country_code.to_s

  trunk_group_carrier.save!
  end

  return trunk_group_carrier
end

def find_dest_vcb(vcb_name, vcb_ip, vcb_data_center)
  vcb = DimenDestVcb.find(:first, :conditions => ["vcb_name=? and vcb_ip=? and vcb_data_center=?", vcb_name, vcb_ip, vcb_data_center])

  if vcb == nil
    vcb = DimenDestVcb.new
    vcb.vcb_name  = vcb_name
    vcb.vcb_ip    = vcb_ip
    vcb.vcb_data_center = vcb_data_center
    vcb.save!
  end

  return vcb
end

def find_trunk_group_col_name(phone_number)
  #TODO: Ansh said 'leave it blank for now - 7/12/2011'
  return "TBI"
end

def get_city_state(phone_number, country_code) # used for src_location
  country_code = get_iso_country_code(phone_number, false)[0] if country_code == nil
  
  #puts "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxx %s" % country_code
  state = "INIT_VAL"
  city  = "INIT_VAL"
  
  error = "ERR"
  
  if country_code == nil
    city  = error
    state = error
  elsif country_code == "US"
    phone_number = phone_number[1..10] if phone_number.start_with?("1")

    state = AREA[phone_number[0..2]][0] if AREA.has_key?(phone_number[0..2])
    city  = AREA[phone_number[0..2]][1] if AREA.has_key?(phone_number[0..2])
    
    state = error if state.to_s.size==0
    city  = error if city.to_s.size==0
  else
    state = country_code
    city  = "INTERNATIONAL"
  end
  
  return state, city
end















##############################################################
##
## Functions Using Phid function
## xxx_plural functions take array of phone_numbers 
## and return hash of phone_numbers
## it is a bit tricky to use this function but is there a better way?
## 
##
##############################################################
def find_group_provider_name_plural(phone_numbers)
  s = phone_numbers.join(",")
  result = phid_use("dest_numbers/provider", s)
  #log("d", "phid result: %s %s" % [result, DateTime.now.to_s])
  #puts "phid input: %s" % s
  #puts "phid output: %s %s" % [result, DateTime.now.to_s]
  json = {}
  
  if result != nil
    begin
      json = JSON.parse(result)
    rescue
      log("phid", "result: %s, params: %s" % [result, s] )
    end
  end

  
  
  
  unknown  = "UNKNOWN"
  provider = "INIT_VAL"
  status   = "INIT_VAL"
  
  return_val = Hash.new
  
  if json == nil
    provider  = unknown
    status        = "NIL FROM PHID"
    
    for number in phone_numbers
      return_val[number] = [provider, status]
    end
  elsif json.length == 0
    provider  = unknown
    status        = "NIL FROM PHID"
    
    for number in phone_numbers
      return_val["number"] = [provider, status]
    end
  end

  for j in json
    if j.has_key? "status"
      if j["status"] == "OK"
        provider      = j["provider"]
        status        = j["status"]
      else
        provider      = unknown
        status        = j["status"]
      end 
    else
      provider      = unknown
      status        = "NOSTAT"
    end
    
    return_val[j["number"]] = [provider, status]
    
  end
  
  return return_val
end

def find_group_provider_name_singular(phone_number)
  result = phid_use("dest_numbers/provider", phone_number)
  #puts "phid result: %s %s" % [result, DateTime.now.to_s]
  
  unknown  = "UNKNOWN"
  provider = "INIT_VAL"
  status   = "INIT_VAL"
  begin
    j = JSON.parse(result)
  rescue
    log("phid", result)
    return unknown
  end
  
  if j == nil
    provider  = unknown
    status        = "NIL FROM PHID"
  elsif j.length == 0
    provider  = unknown
    status        = "NIL FROM PHID"
  end
  
  if j[0].has_key? "status"
    if j[0]["status"] == "OK"
      provider      = j[0]["provider"]
      status        = j[0]["status"]
    else
      provider      = unknown
      status        = j[0]["status"]
    end 
  else
    provider      = unknown
    status        = "NOSTAT"
  end
  
  return provider, status
end

def find_group_provider_name(phone_number, cache)
  if cache == nil
    return find_group_provider_name_singular phone_number
  end
  if cache.has_key? phone_number
    return cache[phone_number]
  else
    return find_group_provider_name_singular phone_number
  end
end

########################################################
##
########################################################

def get_iso_country_code_dest_plural(phone_numbers)
  return if phone_numbers ==  nil
  
  s = phone_numbers.join(",")
  # This function is supposed to use Phid
  result = phid_use("dest_numbers/countrycode", s)
  
  
  if result == nil
    return "phid server error"
  end
  #log("d", "phid result: %s %s" % [result, DateTime.now.to_s])
  begin
    json = JSON.parse(result)
  rescue
    log("json", json)
  end
  unknown       = "UNKNOWN"
  country_code  = "INIT_VAL"
  status        = "INIT_VAL"
  
  return_hash = Hash.new
  
  if json == nil
    country_code  = unknown
    status        = "NIL FROM PHID"
    for i in 0...phone_numbers.size
      return_hash[phone_numbers[i]] = [country_code, status]
    end
  elsif json.length == 0
    country_code  = unknown
    status        = "NIL FROM PHID"
    for i in 0...phone_numbers.size
      return_hash[phone_numbers[i]] = [country_code, status]
    end
  end
  
  if json != nil
    for j in json 
      if j.has_key? "status"
        if j["status"] == "OK"
          country_code = j["country_code"]
          country_code = "US" if country_code == "CA" #We have duplicated record in the db
          status       = j["status"]
        else
          country_code = unknown
          status       = j["status"]
        end 
      else
        country_code = unknown
        status       = "NOSTAT"
      end
      
      return_hash[j["number"]] = [country_code, status]
    end
  end
  
  return return_hash  
  
end

def get_iso_country_code_dest_from_phid(phone_number)
  # This function is supposed to use Phid
  result = phid_use("dest_numbers/countrycode", phone_number)
    
  if result == nil
    return "phid server error"
  end
  #puts "phid result: %s %s" % [result, DateTime.now.to_s]
  j = JSON.parse(result)
  
  unknown       = "UNKNOWN"
  country_code  = "INIT_VAL"
  status        = "INIT_VAL"
  
  if j == nil
    country_code  = unknown
    status        = "NIL FROM PHID"
  elsif j.length == 0
    country_code  = unknown
    status        = "NIL FROM PHID"
  end
  
  if j[0].has_key? "status"
    if j[0]["status"] == "OK"
      country_code = j[0]["country_code"]
      country_code = "US" if country_code == "CA" # We have duplicated record in the db
      status       = j[0]["status"]
    else
      country_code = unknown
      status       = j[0]["status"]
    end 
  else
    country_code = unknown
    status       = "NOSTAT"
  end
  
  #puts "xxxxxxxxxxxxxxxxxxxxxxx555 country code #{country_code}, stats #{status}"
  return country_code, status
  
end

def get_iso_country_code_dest_from_cache(phone_number)
  if @ccode_dest == nil
    return get_iso_country_code_dest_from_phid phone_number
  end
  if @ccode_dest.has_key?(phone_number)
    return @ccode_dest[phone_number]
  else
    return get_iso_country_code_dest_from_phid phone_number
  end
end

def phid_use(function_name, parameter)
begin
  #result = `curl -b cookie3 -H 'Accept: application/json' https://10.1.1.193:3000/#{function_name}?number=#{parameter} -k`
  command = "curl -H 'Accept: application/json' -X POST https://netconf2.ops:3010/#{function_name} -d \"number=#{parameter}\" -c cookie3 -k"
  #log("d", command)
  result = ` #{command} `
  
  log("d", result)
  
  if result.include?("error")
    phid_login()
    phid_use(function_name, parameter)
  end
  
  
  return result
end
  

  ## phid is pain in the but
  ## try this https://netconf2.ops:3002/dest_numbers/provider
  require "net/https"
  http = Net::HTTP.new('netconf2.ops', 3010)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  path = "/#{function_name}"

  data = "number=#{parameter}"
  headers = {
    'Accept' => 'application/json',
    'Referer' => "https://netconf2.ops:3010/#{function_name}",
    'Content-Type' => 'application/x-www-form-urlencoded'}

  resp, json_str = http.post(path, data, headers)

  #puts resp.code
  #puts resp.message
  #puts data # TODO add checking if it is json? then what do i do if it is not json? how to stop whole process? 
  

  return json_str
end

def phid_login()
  username = "user1@gmail.com"
  password = "password1"
  
  result = `curl -H 'Content-Type: application/json' \
            -H 'Accept: application/json' \
            -X POST \
            https://netconf2.ops:3000/users/sign_in -d \
            "{'user' : { 'email' : #{username}, 'password' : #{password}}}" -c cookie2 -k`
  #log("d", "phid login: " + result)
end


#######################################################################################################
###
###
### End of using phid
###
###
#######################################################################################################

def get_iso_country_code_src(phone_number)
  unknown = "UNKNOWN"
  error   = "ERROR"
  ok      = "OK"
  
  iso     = "INIT"
  status  = "INIT"
  
  if phone_number.start_with?("+")
    return get_iso_country_code_src_lookup_from_NUMBER_TO_COUNTRY_CODE(phone_number)
  else
    if phone_number.size == 11 and phone_number.start_with?("1204") #Canada
      iso    = "CA"
      status = ok
    elsif phone_number.size == 11 and phone_number.start_with?("1") and AREA.has_key?(phone_number[1..3]) #US
      iso    = "US"
      status = ok
    elsif phone_number.size == 10 and phone_number.start_with?("204") #Canada
      iso    = "CA"
      status = ok
    elsif phone_number.size == 10  and isNumeric(phone_number) and AREA.has_key?(phone_number[0..2]) #US
      iso    = "US"
      status = ok
    else
      if isNumeric(phone_number)
        iso    = get_iso_country_code_src_lookup_from_NUMBER_TO_COUNTRY_CODE(phone_number)
        status = error
        status = ok if iso != unknown
      else
        iso, status   = unknown, error
      end
    end
  end
  
  
  return iso
end

def isNumeric(s)
  begin
    Integer(s)
  rescue
    false # not numeric
  else
    true # numeric
  end
end

def get_iso_country_code_src_lookup_from_NUMBER_TO_COUNTRY_CODE(phone_number)
  phone_number = phone_number.gsub("+","")
  max_digit = 5  

  for i in 0...max_digit
    if NUMBER_TO_COUNTRY_CODE.has_key?(phone_number[0..i])
      return NUMBER_TO_COUNTRY_CODE[phone_number[0..i]].to_s
    end
  end
  
  return "UNKNOWN"

end
###################################################################################
##
###################################################################################

def get_country_number(country_code)
  return COUNTRY_NUMBER[country_code]["number"] if COUNTRY_NUMBER.has_key?(country_code)
end



def get_mask(iso_country_code) 
  garbage = "1111111111111111111111111111111"
  if COUNTRY_NUMBER.has_key?(iso_country_code) 
    return COUNTRY_NUMBER[iso_country_code]["current_mask"]
  else
    return garbage
  end
end

def get_identifying_phone_number(phone_number, iso_country_code)
  if phone_number.nil? or phone_number.size==0
    return nil
  end

  phone_number = phone_number.gsub("+","")
  mask             = get_mask(iso_country_code)            
  country_number   = get_country_number(iso_country_code)
  
  phone_number = "%s%s" % [country_number, phone_number] if not phone_number.start_with?(country_number)

  identifying_number = ""

  min = mask.size
  if min>phone_number.size
    min = phone_number.size
  end

  for i in 0...min
    if mask[i].chr == "1"
    identifying_number += phone_number[i].chr
    end
  end

  return identifying_number
end

def find_src_location(phone_number, src_carrier, src_ip, iso_country_code)
  i           = get_identifying_phone_number(phone_number, iso_country_code)
  city, state = get_city_state(phone_number, iso_country_code)
  
  #puts "@@@@@@@@@@@@@@@ country code #{iso_country_code}"
  
  src_location = DimenSrcLocation.find( \
  :first, :conditions => \
  ["identifying_phone_number=? \
    and iso_country_code=? \
    and src_carrier=? \
    and src_ip=?", \
    i \
    , iso_country_code \
    , src_carrier \
    , src_ip])

  if src_location == nil
    mask              = get_mask(iso_country_code)
    areacode_for_us   = get_areacode_for_us(phone_number, iso_country_code)  #TODO might be randome if same areacode includes
    
    src_location                          = DimenSrcLocation.new
    src_location.identifying_phone_number = i
    src_location.iso_country_code         = iso_country_code
    src_location.areacode_for_us          = areacode_for_us
    src_location.city                     = city
    src_location.state                    = state
    src_location.mask                     = mask
    src_location.src_carrier              = src_carrier
    src_location.src_ip                   = src_ip
    src_location.save!
  end
  return src_location
  
end

def get_areacode_for_us(phone_number, iso_country_code)
  number = phone_number.gsub("+","")
  areacode = "UNKNOWN"
  
  if iso_country_code == "US"
    area = number[1..3]
    if AREA.has_key? area
      if CURRENT_AVAILABLE_CODE_FROM_GOOGLE.has_key?("US-" + AREA[area][0])
        areacode = "US-" + AREA[area][0]
      end
    end
  end
  
  return areacode
end


def checkPair(pair1, pair2)
  '''
  # Function Name: checkPair
  # This function checks if a pair of one call record is consistent or not. This function needs to be tested fully.
  ##
  '''
  if not (pair1.kind_of? Hash and pair2.kind_of? Hash)
    return false
  end

  if 
  (pair1[SRC_CARRIER] ==pair2[DEST_CARRIER] and
  pair1[SRC_IP]       ==pair2[DEST_IP]      and
  pair1[SRC_PHONE].gsub("+","")    ==pair2[DEST_PHONE].gsub("+","")   and
  pair1[DEST_CARRIER] ==pair2[SRC_CARRIER]  and
  pair1[DEST_IP]      ==pair2[SRC_IP]       and
  pair1[DEST_PHONE].gsub("+","")   ==pair2[SRC_PHONE].gsub("+",""))
    return true
  end

  log('W',"%s %s %s %s %s %s" % [pair1[ID], pair1[SRC_IP], pair1[SRC_PHONE], pair1[DEST_CARRIER], pair1[DEST_IP], pair1[DEST_PHONE]])
  return false
end



def myStrip(dataArray)
  '''
    myStrip function
    This takes out all the unnecessary words such as ip:, ani:, etc
  '''
  if dataArray.kind_of? Hash
    dataArray[SRC_CARRIER]  = dataArray[SRC_CARRIER]                                                      #= src_carrier
    dataArray[SRC_IP]       = dataArray[SRC_IP].gsub("ip:","").strip      if dataArray[SRC_IP] != nil     #= src_ip
    dataArray[SRC_PHONE]    = dataArray[SRC_PHONE].gsub("ani:","").strip  if dataArray[SRC_PHONE] != nil  #= src_phone
    dataArray[DEST_CARRIER] = dataArray[DEST_CARRIER].strip               if dataArray[DEST_CARRIER] != nil             #= dest_carrier
    dataArray[DEST_IP]      = dataArray[DEST_IP].gsub("ip:","").strip     if dataArray[DEST_IP] != nil                  #= dest_ip
    dataArray[DEST_PHONE]   = dataArray[DEST_PHONE].gsub("dnis:","").gsub("+","").strip if dataArray[DEST_PHONE] != nil #= dest_phone
    dataArray[DURATION]     = dataArray[DURATION].gsub("dur:","").gsub("s","").strip    if dataArray[DURATION] != nil   #= duration
    return dataArray
  else
    return nil
  end

end



def iterate_folders(fileroot)
  '''
    It does depth first search for the folder (recursive)
    If a file is a folder, this function calls itself recursively, else parse the file
  '''
  allfiles = Dir[File.join(fileroot, "*")]
  allfiles.each { |i|
    if File.ftype(i) == "directory"
      print i + NL
      iterate_folders(i)
    elsif File.ftype(i) == "file" and File.extname(i) == ".callcache" #callcache means that it is a new file
      processFile(i)
    end
  }
end



def log(level, message)
  outfile = File.new(LOG_FILE_NAME, "a")
  outfile.write("%s,%s,%s\n" % [level, Time.now(), message])
  outfile.close()
end
    
    
    
    
    
 


#######################################################################################
###
###
### These are wrapper functions for testing
###
#######################################################################################
def for_test_find_trunk_group_carrier(src_carrier)
  return DimenTrunkGroupCarrier.find_by_src_carrier(src_carrier)
end

